"""
异常定义模块

定义ES Archive Tool的所有自定义异常类。
"""

from typing import Optional, Dict, Any
from enum import Enum


class ErrorCode(Enum):
    """错误代码枚举"""
    
    # 通用错误 (1000-1999)
    UNKNOWN_ERROR = 1000
    INVALID_CONFIGURATION = 1001
    INVALID_PARAMETER = 1002
    OPERATION_CANCELLED = 1003
    PERMISSION_DENIED = 1004
    
    # ES连接错误 (2000-2999)
    ES_CONNECTION_ERROR = 2000
    ES_AUTHENTICATION_ERROR = 2001
    ES_AUTHORIZATION_ERROR = 2002
    ES_TIMEOUT_ERROR = 2003
    ES_CLUSTER_UNAVAILABLE = 2004
    ES_INDEX_NOT_FOUND = 2005
    ES_MAPPING_ERROR = 2006
    ES_QUERY_ERROR = 2007
    
    # 时间处理错误 (3000-3999)
    TIME_FIELD_NOT_FOUND = 3000
    TIME_FIELD_INVALID = 3001
    TIME_FORMAT_ERROR = 3002
    TIME_RANGE_INVALID = 3003
    TIMEZONE_ERROR = 3004
    TIME_PARSING_ERROR = 3005
    
    # 备份错误 (4000-4999)
    BACKUP_FAILED = 4000
    BACKUP_INTERRUPTED = 4001
    BACKUP_VALIDATION_ERROR = 4002
    BACKUP_METADATA_ERROR = 4003
    BACKUP_CHUNK_ERROR = 4004
    
    # 恢复错误 (5000-5999)
    RESTORE_FAILED = 5000
    RESTORE_INTERRUPTED = 5001
    RESTORE_VALIDATION_ERROR = 5002
    RESTORE_INDEX_ERROR = 5003
    RESTORE_DATA_ERROR = 5004
    
    # 存储错误 (6000-6999)
    STORAGE_ERROR = 6000
    STORAGE_PERMISSION_ERROR = 6001
    STORAGE_SPACE_ERROR = 6002
    STORAGE_IO_ERROR = 6003
    COMPRESSION_ERROR = 6004
    
    # 数据错误 (7000-7999)
    DATA_VALIDATION_ERROR = 7000
    DATA_CORRUPTION_ERROR = 7001
    DATA_FORMAT_ERROR = 7002
    DATA_CONSISTENCY_ERROR = 7003


class ESArchiveError(Exception):
    """ES Archive Tool 基础异常类"""
    
    def __init__(
        self,
        message: str,
        error_code: ErrorCode = ErrorCode.UNKNOWN_ERROR,
        details: Optional[Dict[str, Any]] = None,
        cause: Optional[Exception] = None
    ):
        """初始化异常
        
        Args:
            message: 错误消息
            error_code: 错误代码
            details: 错误详情
            cause: 原始异常
        """
        super().__init__(message)
        self.message = message
        self.error_code = error_code
        self.details = details or {}
        self.cause = cause
    
    def __str__(self) -> str:
        """字符串表示"""
        return f"[{self.error_code.name}] {self.message}"
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            "error_code": self.error_code.value,
            "error_name": self.error_code.name,
            "message": self.message,
            "details": self.details,
            "cause": str(self.cause) if self.cause else None
        }


class ConfigurationError(ESArchiveError):
    """配置错误"""
    
    def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
        super().__init__(
            message,
            ErrorCode.INVALID_CONFIGURATION,
            details
        )


class ParameterError(ESArchiveError):
    """参数错误"""
    
    def __init__(self, message: str, parameter: str, value: Any = None):
        details = {"parameter": parameter}
        if value is not None:
            details["value"] = value
        
        super().__init__(
            message,
            ErrorCode.INVALID_PARAMETER,
            details
        )


class ESConnectionError(ESArchiveError):
    """ES连接错误"""
    
    def __init__(self, message: str, host: Optional[str] = None, cause: Optional[Exception] = None):
        details = {}
        if host:
            details["host"] = host
        
        super().__init__(
            message,
            ErrorCode.ES_CONNECTION_ERROR,
            details,
            cause
        )


class ESAuthenticationError(ESArchiveError):
    """ES认证错误"""
    
    def __init__(self, message: str, username: Optional[str] = None):
        details = {}
        if username:
            details["username"] = username
        
        super().__init__(
            message,
            ErrorCode.ES_AUTHENTICATION_ERROR,
            details
        )


class ESIndexNotFoundError(ESArchiveError):
    """ES索引不存在错误"""
    
    def __init__(self, index_name: str):
        super().__init__(
            f"索引不存在: {index_name}",
            ErrorCode.ES_INDEX_NOT_FOUND,
            {"index_name": index_name}
        )


class TimeFieldError(ESArchiveError):
    """时间字段错误"""
    
    def __init__(self, message: str, field_name: Optional[str] = None, error_code: ErrorCode = ErrorCode.TIME_FIELD_INVALID):
        details = {}
        if field_name:
            details["field_name"] = field_name
        
        super().__init__(message, error_code, details)


class TimeFormatError(ESArchiveError):
    """时间格式错误"""
    
    def __init__(self, message: str, time_value: Optional[str] = None, expected_format: Optional[str] = None):
        details = {}
        if time_value:
            details["time_value"] = time_value
        if expected_format:
            details["expected_format"] = expected_format
        
        super().__init__(
            message,
            ErrorCode.TIME_FORMAT_ERROR,
            details
        )


class TimeRangeError(ESArchiveError):
    """时间范围错误"""
    
    def __init__(self, message: str, start_time: Optional[str] = None, end_time: Optional[str] = None):
        details = {}
        if start_time:
            details["start_time"] = start_time
        if end_time:
            details["end_time"] = end_time
        
        super().__init__(
            message,
            ErrorCode.TIME_RANGE_INVALID,
            details
        )


class BackupError(ESArchiveError):
    """备份错误"""
    
    def __init__(self, message: str, backup_path: Optional[str] = None, cause: Optional[Exception] = None):
        details = {}
        if backup_path:
            details["backup_path"] = backup_path
        
        super().__init__(
            message,
            ErrorCode.BACKUP_FAILED,
            details,
            cause
        )


class RestoreError(ESArchiveError):
    """恢复错误"""
    
    def __init__(self, message: str, target_index: Optional[str] = None, cause: Optional[Exception] = None):
        details = {}
        if target_index:
            details["target_index"] = target_index
        
        super().__init__(
            message,
            ErrorCode.RESTORE_FAILED,
            details,
            cause
        )


class StorageError(ESArchiveError):
    """存储错误"""
    
    def __init__(self, message: str, path: Optional[str] = None, cause: Optional[Exception] = None):
        details = {}
        if path:
            details["path"] = path
        
        super().__init__(
            message,
            ErrorCode.STORAGE_ERROR,
            details,
            cause
        )


class DataValidationError(ESArchiveError):
    """数据验证错误"""
    
    def __init__(self, message: str, validation_type: Optional[str] = None, details: Optional[Dict[str, Any]] = None):
        error_details = details or {}
        if validation_type:
            error_details["validation_type"] = validation_type
        
        super().__init__(
            message,
            ErrorCode.DATA_VALIDATION_ERROR,
            error_details
        )


class OperationCancelledError(ESArchiveError):
    """操作取消错误"""
    
    def __init__(self, operation: str):
        super().__init__(
            f"操作被取消: {operation}",
            ErrorCode.OPERATION_CANCELLED,
            {"operation": operation}
        )


class RetryableError(ESArchiveError):
    """可重试错误
    
    标记可以重试的错误类型。
    """
    
    def __init__(self, message: str, error_code: ErrorCode, max_retries: int = 3, details: Optional[Dict[str, Any]] = None):
        super().__init__(message, error_code, details)
        self.max_retries = max_retries
        self.retry_count = 0
    
    def can_retry(self) -> bool:
        """检查是否可以重试"""
        return self.retry_count < self.max_retries
    
    def increment_retry(self) -> None:
        """增加重试次数"""
        self.retry_count += 1


class NonRetryableError(ESArchiveError):
    """不可重试错误
    
    标记不应该重试的错误类型。
    """
    pass


# 错误分类映射
RETRYABLE_ERROR_CODES = {
    ErrorCode.ES_CONNECTION_ERROR,
    ErrorCode.ES_TIMEOUT_ERROR,
    ErrorCode.ES_CLUSTER_UNAVAILABLE,
    ErrorCode.STORAGE_IO_ERROR,
    ErrorCode.BACKUP_INTERRUPTED,
    ErrorCode.RESTORE_INTERRUPTED,
}

NON_RETRYABLE_ERROR_CODES = {
    ErrorCode.ES_AUTHENTICATION_ERROR,
    ErrorCode.ES_AUTHORIZATION_ERROR,
    ErrorCode.ES_INDEX_NOT_FOUND,
    ErrorCode.INVALID_CONFIGURATION,
    ErrorCode.INVALID_PARAMETER,
    ErrorCode.TIME_FIELD_NOT_FOUND,
    ErrorCode.TIME_FORMAT_ERROR,
    ErrorCode.PERMISSION_DENIED,
    ErrorCode.DATA_VALIDATION_ERROR,
}


def is_retryable_error(error: Exception) -> bool:
    """检查错误是否可重试
    
    Args:
        error: 异常对象
        
    Returns:
        是否可重试
    """
    if isinstance(error, RetryableError):
        return error.can_retry()
    
    if isinstance(error, NonRetryableError):
        return False
    
    if isinstance(error, ESArchiveError):
        return error.error_code in RETRYABLE_ERROR_CODES
    
    # 对于非ES Archive错误，根据类型判断
    import elasticsearch
    if isinstance(error, (elasticsearch.ConnectionError, elasticsearch.ConnectionTimeout)):
        return True
    
    if isinstance(error, (elasticsearch.AuthenticationException, elasticsearch.AuthorizationException)):
        return False
    
    # 默认不重试
    return False


def create_error_from_exception(exc: Exception, message: Optional[str] = None) -> ESArchiveError:
    """从标准异常创建ES Archive错误
    
    Args:
        exc: 原始异常
        message: 自定义错误消息
        
    Returns:
        ES Archive错误
    """
    if isinstance(exc, ESArchiveError):
        return exc
    
    error_message = message or str(exc)
    
    # ES相关错误
    import elasticsearch
    if isinstance(exc, elasticsearch.ConnectionError):
        return ESConnectionError(error_message, cause=exc)
    elif isinstance(exc, elasticsearch.AuthenticationException):
        return ESAuthenticationError(error_message, cause=exc)
    elif isinstance(exc, elasticsearch.NotFoundError):
        return ESIndexNotFoundError(error_message)
    elif isinstance(exc, elasticsearch.RequestError):
        return ESArchiveError(error_message, ErrorCode.ES_QUERY_ERROR, cause=exc)
    
    # 文件系统错误
    elif isinstance(exc, (IOError, OSError)):
        return StorageError(error_message, cause=exc)
    elif isinstance(exc, PermissionError):
        return ESArchiveError(error_message, ErrorCode.PERMISSION_DENIED, cause=exc)
    
    # 值错误
    elif isinstance(exc, ValueError):
        return ParameterError(error_message, "unknown", cause=exc)
    
    # 其他错误
    else:
        return ESArchiveError(error_message, ErrorCode.UNKNOWN_ERROR, cause=exc)
